import React, { ReactNode, useState, useEffect, useCallback } from 'react';
import classNames from 'classnames';

import { Item } from './walk';

const DEFAULT_PADDING = 0.75;
const ICON_SIZE = 2;
const LEVEL_SPACE = 1.25;
const ToggleIcon = ({
  on,
  openedIcon,
  closedIcon,
}: {
  on: boolean;
  openedIcon: ReactNode;
  closedIcon: ReactNode;
}) => (
  <div role="img" aria-label="Toggle" className="rstm-toggle-icon-symbol">
    {on ? openedIcon : closedIcon}
  </div>
);

const ToggleEndIcon = ({
  iconClick,
  showIcon,
  hiddenIcon,
  onClickIcon,
  useIcon
}: {
  iconClick: boolean;
  showIcon: ReactNode;
  hiddenIcon: ReactNode;
  onClickIcon: any,
  useIcon: boolean
}) => {
  let iconEle = iconClick ? showIcon : hiddenIcon;

  if(!useIcon) {
    iconEle = '';
  }

  return (
    <div role="img" aria-label="Toggle"
         className="rstm-end-icon"
         onClick={e => {
           onClickIcon && onClickIcon();
           e.stopPropagation();
         }}>
      {iconEle}
    </div>
  );
};

const AnotherToggleEndIcon = ({
                         iconClick,
                         showIcon,
                         hiddenIcon,
                         onClickIcon,
                         useIcon
                       }: {
  iconClick: boolean;
  showIcon: ReactNode;
  hiddenIcon: ReactNode;
  onClickIcon: any,
  useIcon: boolean
}) => {
  let iconEle = iconClick ? showIcon : hiddenIcon;

  if(!useIcon) {
    iconEle = '';
  }

  return (
    <div role="img" aria-label="Toggle"
         className="rstm-another-end-icon"
         onClick={e => {
           onClickIcon && onClickIcon();
           e.stopPropagation();
         }}>
      {iconEle}
    </div>
  );
};

export interface TreeMenuItem extends Item {
  active?: boolean;
  onClick: (event: React.MouseEvent<HTMLLIElement>) => void;
  onClickIcon?: (e: any) => void;
  onAnotherClickIcon?: (e: any) => void,
  toggleNode?: () => void;
}

export type TreeMenuChildren = (props: {
  search?: (term: string) => void;
  searchTerm?: string;
  items: TreeMenuItem[];
  resetOpenNodes?: (openNodes?: string[]) => void;
}) => JSX.Element;

const OpenIcon = (
  <svg className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
    p-id="2827" width="14" height="14">
    <path
      d="M747.52 414.72c10.24-10.24 10.24-25.6 0-35.84-10.24-10.24-23.04-10.24-33.28-2.56l-2.56 2.56-197.12 197.12H512l-197.12-197.12c-10.24-10.24-25.6-10.24-35.84 0-10.24 10.24-10.24 23.04-2.56 33.28l2.56 2.56 197.12 197.12c20.48 20.48 51.2 20.48 71.68 2.56l2.56-2.56 197.12-197.12z"
      fill="#666666" p-id="2828"></path>
  </svg>
);

const CloseIcon = (
  <svg className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
    p-id="3211" width="14" height="14">
    <path
      d="M427.52 747.52c-10.24 10.24-25.6 10.24-35.84 0-10.24-10.24-10.24-23.04-2.56-33.28l2.56-2.56 197.12-197.12V512l-197.12-197.12c-10.24-10.24-10.24-25.6 0-35.84 10.24-10.24 23.04-10.24 33.28-2.56l2.56 2.56 197.12 197.12c20.48 20.48 20.48 51.2 2.56 71.68l-2.56 2.56-197.12 197.12z"
      fill="#666666" p-id="3212"></path>
  </svg>
);


const ShowIcon = (
  <svg className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3364" width="20" height="20"><defs><style type="text/css"></style></defs><path d="M512 298.666667c-162.133333 0-285.866667 68.266667-375.466667 213.333333 89.6 145.066667 213.333333 213.333333 375.466667 213.333333s285.866667-68.266667 375.466667-213.333333c-89.6-145.066667-213.333333-213.333333-375.466667-213.333333z m0 469.333333c-183.466667 0-328.533333-85.333333-426.666667-256 98.133333-170.666667 243.2-256 426.666667-256s328.533333 85.333333 426.666667 256c-98.133333 170.666667-243.2 256-426.666667 256z m0-170.666667c46.933333 0 85.333333-38.4 85.333333-85.333333s-38.4-85.333333-85.333333-85.333333-85.333333 38.4-85.333333 85.333333 38.4 85.333333 85.333333 85.333333z m0 42.666667c-72.533333 0-128-55.466667-128-128s55.466667-128 128-128 128 55.466667 128 128-55.466667 128-128 128z" fill="#444444" p-id="3365"></path></svg>
);

const HiddenIcon = (
  <svg className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3495" width="20" height="20"><defs><style type="text/css"></style></defs><path d="M332.8 729.6l34.133333-34.133333c42.666667 12.8 93.866667 21.333333 145.066667 21.333333 162.133333 0 285.866667-68.266667 375.466667-213.333333-46.933333-72.533333-102.4-128-166.4-162.133334l29.866666-29.866666c72.533333 42.666667 132.266667 106.666667 183.466667 192-98.133333 170.666667-243.2 256-426.666667 256-59.733333 4.266667-119.466667-8.533333-174.933333-29.866667z m-115.2-64c-51.2-38.4-93.866667-93.866667-132.266667-157.866667 98.133333-170.666667 243.2-256 426.666667-256 38.4 0 76.8 4.266667 110.933333 12.8l-34.133333 34.133334c-25.6-4.266667-46.933333-4.266667-76.8-4.266667-162.133333 0-285.866667 68.266667-375.466667 213.333333 34.133333 51.2 72.533333 93.866667 115.2 128l-34.133333 29.866667z m230.4-46.933333l29.866667-29.866667c8.533333 4.266667 21.333333 4.266667 29.866666 4.266667 46.933333 0 85.333333-38.4 85.333334-85.333334 0-12.8 0-21.333333-4.266667-29.866666l29.866667-29.866667c12.8 17.066667 17.066667 38.4 17.066666 64 0 72.533333-55.466667 128-128 128-17.066667-4.266667-38.4-12.8-59.733333-21.333333zM384 499.2c4.266667-68.266667 55.466667-119.466667 123.733333-123.733333 0 4.266667-123.733333 123.733333-123.733333 123.733333zM733.866667 213.333333l29.866666 29.866667-512 512-34.133333-29.866667L733.866667 213.333333z" fill="#444444" p-id="3496"></path></svg>
);

export const ItemComponent: React.FunctionComponent<TreeMenuItem> = ({
  AnotherVisible,
  visible,
  total,
  hasNodes = false,
  isOpen = false,
  level = 0,
  onClick,
  toggleNode,
  onClickIcon,
  onAnotherClickIcon ,
  active,
  focused,
  openedIcon = OpenIcon,
  closedIcon = CloseIcon,
  showIcon = ShowIcon,
  hiddenIcon = HiddenIcon,
  useIcon = true,
  label = 'unknown',
  style = {},
}) => {
  const [hover, setHover] = useState(0);

  const handleMouseEnter = (e: React.MouseEvent<HTMLLIElement>) => {
    if(useIcon)
      setHover(1);
  };

  const handleMouseLeave = (e: React.MouseEvent<HTMLLIElement>) => {
    if(useIcon)
      setHover(0);
  }

  let totalEle = visible && total ? <div className="rstm-total">{total}</div> : '';

  if(useIcon) {
    totalEle = total ? <div className="rstm-total">{total}</div> : '';
  }

  return (
    <li
      className={classNames(
        'rstm-tree-item',
        `rstm-tree-item-level${level}`,
        { 'rstm-tree-item--active': active },
        { 'rstm-tree-item--focused': focused },
        { 'has-icon-hover': hover },
        { 'show-icon': !visible }
      )}
      style={{
        paddingLeft: `${DEFAULT_PADDING +
          ICON_SIZE * (hasNodes ? 0 : 0.5) +
          level * LEVEL_SPACE}rem`,
        ...style,
      }}
      role="button"
      aria-pressed={active}
      onClick={onClick}
      onMouseEnter={e => handleMouseEnter(e)}
      onMouseLeave={e => handleMouseLeave(e)}
    >
      {hasNodes && (
        <div
          className="rstm-toggle-icon"
          onClick={e => {
            hasNodes && toggleNode && toggleNode();
            e.stopPropagation();
          }}
        >
          <ToggleIcon on={isOpen} openedIcon={openedIcon} closedIcon={closedIcon} />
        </div>
      )}


      <div className='rstm-label' title={label}>{label.length>8?label.substring(0,12)+'...':label}</div>
      {totalEle}
      {onAnotherClickIcon ? <AnotherToggleEndIcon iconClick={AnotherVisible} showIcon={ShowIcon} hiddenIcon={HiddenIcon} onClickIcon={() => onAnotherClickIcon(label)} useIcon={useIcon}/> : ''}
      {onClickIcon ? <ToggleEndIcon iconClick={visible} showIcon={showIcon} hiddenIcon={hiddenIcon} onClickIcon={() => onClickIcon(label)} useIcon={useIcon}/> : ''}
    </li>
  )
};

export const defaultChildren: TreeMenuChildren = ({ search, items }) => {
  const onSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { value } = e.target;
    search && search(value);
  };

  return (
    <>
      {search && (
        <input
          className="rstm-search"
          aria-label="Type and search"
          type="search"
          placeholder="Type and search"
          onChange={onSearch}
        />
      )}
      <ul className="rstm-tree-item-group">
        {items.map(({ key, ...props }) => {
          return (<ItemComponent key={key} {...props}></ItemComponent>)
        })}
      </ul>
    </>
  );
};
